package cn.dengta.context.model;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import cn.dengta.common.context.Env;
import cn.dengta.common.model.ValueProxy;
import cn.dengta.common.model.ValueProxyImpl;
import cn.dengta.common.util.Common;
import cn.dengta.common.web.Client;
import cn.dengta.context.web.ProxyRequest;
import cn.dengta.webapp.base.entity.ChannelName;
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;
import me.codeplayer.util.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import static cn.dengta.context.model.UserI18nKey.FLALA_EMAIL;
import static cn.dengta.context.model.UserI18nKey.LIAOYU_EMAIL;

/**
 * 马甲包类型
 */
@Getter
public enum WesKit implements ValueProxyImpl<WesKit, Integer> {

	/** main */
	main(0, "Inchat", ChannelName.main, "Inchat", Member.idPrefix(), false, 101010L, false, false),

	;

	public static final Map<WesKit, Integer> wesKit_tag_count = new HashMap<>();
	/** 域名 */
	public static final Map<WesKit, String> domain_map = new HashMap<>();
	/** 分包邮箱 */
	public static final Map<WesKit, String> weskit_email_map = new HashMap<>();

	static {
		wesKit_tag_count.put(main, 3);

		/** 域名 */
		domain_map.put(WesKit.main, "guangxijunxuan.cn");
		weskit_email_map.put(WesKit.main, FLALA_EMAIL);

	}

	@EnumValue
	public Integer value;
	public Long minId;
	/** 包名 */
	public ChannelName channelName;
	/** 是否为马甲包 */
	public boolean isVest;
	public String appName;
	/** ID前缀 */
	public String idPrefix;
	/** 是否国内版 */
	public boolean interior;
	/** 是否支持新版自定义价格 */
	public boolean customPrice;
	final ValueProxy<WesKit, Integer> proxy;

	WesKit(Integer value, String label, ChannelName channelName, String appName, String idPrefix, boolean isVest, Long minId, boolean interior, boolean customPrice) {
		this.value = value;
		this.channelName = channelName;
		this.isVest = isVest;
		this.appName = appName;
		this.idPrefix = idPrefix;
		this.minId = minId;
		this.interior = interior;
		this.customPrice = customPrice;
		this.proxy = new ValueProxy<>(this, value, label);
	}

	WesKit(Integer value, String label, ChannelName channelName, String appName, String idPrefix, Long minId, boolean interior, boolean customPrice) {
		this(value, label, channelName, appName, idPrefix, true, minId, interior, customPrice);
	}

	public String getPackage(Client client) {
		return client == Client.APP_IOS ? channelName.iosPackage : channelName.androidPackage;
	}

	public static final WesKit[] CACHE = WesKit.values();

	/** ID前缀缓存 */
	public static final Set<String> ID_PREFIX_CACHE = Stream.of(CACHE).map(WesKit::getIdPrefix).collect(Collectors.toSet());

	public static WesKit ofWesKit() {
		return ofWesKit(true);
	}

	public static final String getDomainPrefix(WesKit wesKit, boolean isPrefix) {
		if (domain_map.containsKey(wesKit)) {
			return (isPrefix ? "." : "") + domain_map.get(wesKit);
		}
		return null;
	}

	public static WesKit ofWesKit(boolean def) {
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		if (attributes != null) {
			return ofAppId(ProxyRequest.getAppId(attributes.getRequest()), def);
		}
		return def ? WesKit.main : null;
	}

	public Long maxId() {
		// 当前马甲包最大ID，下一个马甲包最小ID
		int ordinal = ordinal();
		if (ordinal + 1 < CACHE.length) {
			return CACHE[ordinal + 1].minId - 1;
		}
		// 最后一个马甲包,返回Long.MAX_VALUE
		return Long.MAX_VALUE;
	}

	public Long getMaxId() {
		return maxId();
	}

	public boolean isMain() {
		return this == main;
	}

	/**
	 * 是否包含AI
	 */
	public boolean isContainAi() {
		return false;
	}

	public static WesKit ofAppId(String appId) {
		return ofAppId(appId, true);
	}

	/** 通过请求头APP-ID（Flala/Android/4.3.3/google）解析 */
	public static WesKit ofAppId(String appId, boolean setDefault) {
		if (StringUtil.notEmpty(appId)) {
			final String appName = ProxyRequest.getAppName(appId);
			if (StringUtil.notEmpty(appName)) {
				for (WesKit wesKit : CACHE) {
					if (wesKit.appName.equals(appName)) {
						return wesKit;
					}
				}
			}
		}
		return setDefault ? main : null;
	}

	public static WesKit of(@Nullable Integer value) {
		return Common.getEnum(CACHE, WesKit::getValue, value);
	}

	public static boolean startsWith(@Nullable String encodedId) {
		return StringUtil.notEmpty(encodedId) && ID_PREFIX_CACHE.stream().anyMatch(encodedId::startsWith);
	}

	public static String userIdSeq(@Nonnull WesKit wesKit) {
		return "userId_seq:" + wesKit.name();
	}

	public static String calcIdPrefix(Long userId) {
		return calcIdPrefix(userId, true);
	}

	public static String calcIdPrefix(Long userId, boolean setDefault) {
		if (userId != null && Env.inProduction()) {
			for (int i = CACHE.length - 1; i >= 0; i--) {
				if (userId >= CACHE[i].minId) {
					return CACHE[i].idPrefix;
				}
			}
		}
		return setDefault ? Member.idPrefix() : null;
	}

	public static WesKit ofIdPrefix(String idPrefix) {
		for (int i = CACHE.length - 1; i >= 0; i--) {
			if (CACHE[i].idPrefix.equals(idPrefix)) {
				return CACHE[i];
			}
		}
		return null;
	}

	/** 判断用户所属马甲包 */
	public static WesKit ofIdWesKit(Long userId) {
		for (int i = CACHE.length - 1; i >= 0; i--) {
			if (CACHE[i].minId <= userId) {
				return CACHE[i];
			}
		}
		return main;
	}

	/**
	 * 根据环境获取idPrefix
	 */
	public static String idPrefix(Env env, @Nullable Long userId) {
		switch (env) {
			case PROD:
				return X.expectNotNull(calcIdPrefix(userId, false), ID_PREFIX);
			case UAT:
				return UAT_ID_PREFIX;
			case TEST:
				return TEST_ID_PREFIX;
			default:
				return DEV_ID_PREFIX;
		}
	}

	/**
	 * 生产环境主包与分包前缀不一样，其他环境一致
	 */
	public static boolean anyMatchPrefix(String encodeId) {
		if (StringUtil.isEmpty(encodeId)) {
			return false;
		}
		String charAt = String.valueOf(encodeId.charAt(0));
		return ((Env.inProduction() && WesKit.ID_PREFIX_CACHE.contains(charAt))) || ArrayUtil.ins(charAt, UAT_ID_PREFIX, TEST_ID_PREFIX, DEV_ID_PREFIX);
	}

	public static Env envByIdPrefix(String prefix) {
		switch (prefix) {
			case UAT_ID_PREFIX:
				return Env.UAT;
			case TEST_ID_PREFIX:
				return Env.TEST;
			case DEV_ID_PREFIX:
				return Env.DEV;
			default:
				return WesKit.ID_PREFIX_CACHE.contains(prefix) ? Env.PROD : Env.DEV;
		}
	}

	/** 指定分包是否生效 */
	public static boolean isWesKit(WesKit wesKit, String wesKitStr) {
		if (StringUtil.isEmpty(wesKitStr) || wesKit == null) {
			return false;
		}
		if ("-1".equals(wesKitStr)) {
			return true;
		}
		List<Integer> split = Common.splitAsIntList(wesKitStr);
		for (Integer i : split) {
			if (wesKit.eq(i)) {
				return true;
			}
		}
		return false;
	}

	public static String getWesKits_(String wesKits) {
		if (StringUtil.isEmpty(wesKits)) {
			return null;
		}
		List<Integer> split = Common.split(wesKits, Common.CHAR_SEP, Integer::parseInt, true);
		return Common.join(split, (wesKit) -> WesKit.of(wesKit).getLabel(), Common.SEP);
	}

	/**
	 * 示例：
	 *
	 * @param wesKit 1,2,3
	 * @param column wes_kit
	 */
	public static String domainKitSqlStr(String wesKit, String column) {
		if (StringUtil.notEmpty(column) && StringUtil.notEmpty(wesKit)) {
			List<Integer> list = Common.splitAsIntList(wesKit);
			StringBuilder sb = new StringBuilder();
			sb.append(" (");
			int size = list.size();
			int i = 0;
			for (Integer kit : list) {
				sb.append("(");
				sb.append(column);
				sb.append(" BETWEEN ");
				WesKit wk = WesKit.of(kit);
				sb.append(wk.getMinId());
				sb.append(" AND ");
				sb.append(wk.getMaxId());
				sb.append(")");
				i++;
				if (i < size) {
					sb.append(" OR ");
				}
			}
			sb.append(") ");
			return sb.toString();
		}
		return null;
	}

	private static final String ID_PREFIX = "i";
	private static final String UAT_ID_PREFIX = "u";
	private static final String TEST_ID_PREFIX = "t";
	private static final String DEV_ID_PREFIX = "d";

}
